package tag

import (
	"context"
	"time"

	"BookStack/internal/domain/events"
	"BookStack/internal/domain/tag"
	"BookStack/pkg/utils"
)

// Service 标签应用服务接口
type Service interface {
	// ListTags 获取标签列表
	ListTags(ctx context.Context, params *TagListQueryParams) (*TagListResponse, error)

	// GetTag 获取标签详情
	GetTag(ctx context.Context, id uint) (*TagResponse, error)

	// GetTagBySlug 根据Slug获取标签
	GetTagBySlug(ctx context.Context, slug string) (*TagResponse, error)

	// GetHotTags 获取热门标签
	GetHotTags(ctx context.Context, tagType *int, limit int) ([]*TagResponse, error)

	// CreateTag 创建标签
	CreateTag(ctx context.Context, req *CreateTagRequest) (*TagResponse, error)

	// UpdateTag 更新标签
	UpdateTag(ctx context.Context, req *UpdateTagRequest) (*TagResponse, error)

	// DeleteTag 删除标签
	DeleteTag(ctx context.Context, id uint) error

	// BatchDeleteTags 批量删除标签
	BatchDeleteTags(ctx context.Context, ids []uint) error

	// GetTagStat 获取标签使用统计
	GetTagStat(ctx context.Context, id uint) (*TagStatResponse, error)
}

// service 标签应用服务实现
type service struct {
	tagService     tag.Service
	eventPublisher events.Publisher
}

// NewService 创建标签应用服务
func NewService(tagService tag.Service, eventPublisher events.Publisher) Service {
	return &service{
		tagService:     tagService,
		eventPublisher: eventPublisher,
	}
}

// ListTags 获取标签列表
func (s *service) ListTags(ctx context.Context, params *TagListQueryParams) (*TagListResponse, error) {
	// 转换查询参数为领域查询参数
	domainParams := &tag.ListParams{
		Type: params.Type,
		Page: params.Page,
		Size: params.PageSize,
	}

	// 设置默认值
	if domainParams.Page <= 0 {
		domainParams.Page = 1
	}
	if domainParams.Size <= 0 {
		domainParams.Size = 20
	} else if domainParams.Size > 100 {
		domainParams.Size = 100
	}

	// 调用领域服务查询标签列表
	tags, total, err := s.tagService.ListTags(ctx, domainParams)
	if err != nil {
		return nil, WrapError(err)
	}

	// 转换为DTO
	responses := make([]*TagResponse, 0, len(tags))
	for _, t := range tags {
		responses = append(responses, FromEntity(t))
	}

	return &TagListResponse{
		Total: total,
		List:  responses,
	}, nil
}

// GetTag 获取标签详情
func (s *service) GetTag(ctx context.Context, id uint) (*TagResponse, error) {
	// 调用领域服务获取标签
	tag, err := s.tagService.GetTag(ctx, id)
	if err != nil {
		return nil, WrapError(err)
	}
	if tag == nil {
		return nil, TagNotFound(id)
	}

	// 转换为DTO
	return FromEntity(tag), nil
}

// GetTagBySlug 根据Slug获取标签
func (s *service) GetTagBySlug(ctx context.Context, slug string) (*TagResponse, error) {
	// 调用领域服务获取标签
	tag, err := s.tagService.GetTagBySlug(ctx, slug)
	if err != nil {
		return nil, WrapError(err)
	}
	if tag == nil {
		return nil, TagNotFound(slug)
	}

	// 转换为DTO
	return FromEntity(tag), nil
}

// GetHotTags 获取热门标签
func (s *service) GetHotTags(ctx context.Context, tagType *int, limit int) ([]*TagResponse, error) {
	// 调用领域服务获取热门标签
	tags, err := s.tagService.GetHotTags(ctx, tagType, limit)
	if err != nil {
		return nil, WrapError(err)
	}

	// 转换为DTO
	responses := make([]*TagResponse, 0, len(tags))
	for _, t := range tags {
		responses = append(responses, FromEntity(t))
	}

	return responses, nil
}

// CreateTag 创建标签
func (s *service) CreateTag(ctx context.Context, req *CreateTagRequest) (*TagResponse, error) {
	// 检查名称是否已存在于同一类型中
	exists, err := s.tagService.ExistsByName(ctx, req.Name, req.Type, 0)
	if err != nil {
		return nil, WrapError(err)
	}
	if exists {
		return nil, TagNameExists(req.Name, req.Type)
	}

	// 检查Slug是否已存在于同一类型中
	exists, err = s.tagService.ExistsBySlug(ctx, req.Slug, req.Type, 0)
	if err != nil {
		return nil, WrapError(err)
	}
	if exists {
		return nil, TagSlugExists(req.Slug, req.Type)
	}

	// 调用领域服务创建标签
	tag, err := s.tagService.CreateTag(ctx, req.Name, req.Slug, req.Description, req.Type)
	if err != nil {
		return nil, WrapError(err)
	}

	// 发布事件
	now, _ := time.Parse(utils.StandardTimeFormat, utils.Now())
	event := &events.TagCreatedEvent{
		ID:          tag.ID,
		Name:        tag.Name,
		Slug:        tag.Slug,
		Type:        tag.Type,
		Description: tag.Description,
		CreatedBy:   0, // 未登录系统或没有传入用户ID的情况
		CreatedAt:   utils.TimeToJSONTime(now),
	}
	s.eventPublisher.AsyncPublish(ctx, events.NewEvent(events.TagCreatedEventType, event))

	// 转换为DTO
	return FromEntity(tag), nil
}

// UpdateTag 更新标签
func (s *service) UpdateTag(ctx context.Context, req *UpdateTagRequest) (*TagResponse, error) {
	// 获取现有标签
	existingTag, err := s.tagService.GetTag(ctx, req.ID)
	if err != nil {
		return nil, WrapError(err)
	}
	if existingTag == nil {
		return nil, TagNotFound(req.ID)
	}

	// 如果名称发生变化，检查新名称是否已存在于同一类型中
	if existingTag.Name != req.Name {
		exists, err := s.tagService.ExistsByName(ctx, req.Name, req.Type, req.ID)
		if err != nil {
			return nil, WrapError(err)
		}
		if exists {
			return nil, TagNameExists(req.Name, req.Type)
		}
	}

	// 如果slug发生变化，检查新slug是否已存在于同一类型中
	if existingTag.Slug != req.Slug {
		exists, err := s.tagService.ExistsBySlug(ctx, req.Slug, req.Type, req.ID)
		if err != nil {
			return nil, WrapError(err)
		}
		if exists {
			return nil, TagSlugExists(req.Slug, req.Type)
		}
	}

	// 调用领域服务更新标签
	tag, err := s.tagService.UpdateTag(ctx, req.ID, req.Name, req.Slug, req.Description, req.Type)
	if err != nil {
		return nil, WrapError(err)
	}

	// 发布事件
	now, _ := time.Parse(utils.StandardTimeFormat, utils.Now())
	event := &events.TagUpdatedEvent{
		ID:          tag.ID,
		Name:        tag.Name,
		Slug:        tag.Slug,
		Type:        tag.Type,
		Description: tag.Description,
		UpdatedBy:   0, // 未登录系统或没有传入用户ID的情况
		UpdatedAt:   utils.TimeToJSONTime(now),
	}
	s.eventPublisher.AsyncPublish(ctx, events.NewEvent(events.TagUpdatedEventType, event))

	// 转换为DTO
	return FromEntity(tag), nil
}

// DeleteTag 删除标签
func (s *service) DeleteTag(ctx context.Context, id uint) error {
	// 获取标签信息，用于发布事件
	tag, err := s.tagService.GetTag(ctx, id)
	if err != nil {
		return WrapError(err)
	}
	if tag == nil {
		return TagNotFound(id)
	}

	// 调用领域服务删除标签
	if err := s.tagService.DeleteTag(ctx, id); err != nil {
		return WrapError(err)
	}

	// 发布事件
	now, _ := time.Parse(utils.StandardTimeFormat, utils.Now())
	event := &events.TagDeletedEvent{
		ID:        id,
		Name:      tag.Name,
		Slug:      tag.Slug,
		Type:      tag.Type,
		DeletedBy: 0, // 未登录系统或没有传入用户ID的情况
		DeletedAt: utils.TimeToJSONTime(now),
	}
	s.eventPublisher.AsyncPublish(ctx, events.NewEvent(events.TagDeletedEventType, event))

	return nil
}

// BatchDeleteTags 批量删除标签
func (s *service) BatchDeleteTags(ctx context.Context, ids []uint) error {
	// 先获取所有标签信息，用于发布事件
	var tagInfos []events.TagInfo
	for _, id := range ids {
		tag, err := s.tagService.GetTag(ctx, id)
		if err != nil {
			continue
		}
		if tag == nil {
			return TagNotFound(id)
		}
		tagInfos = append(tagInfos, events.TagInfo{
			ID:          tag.ID,
			Name:        tag.Name,
			Slug:        tag.Slug,
			Type:        tag.Type,
			Description: tag.Description,
		})
	}

	// 调用领域服务批量删除标签
	if err := s.tagService.BatchDeleteTags(ctx, ids); err != nil {
		return WrapError(err)
	}

	// 发布事件
	now, _ := time.Parse(utils.StandardTimeFormat, utils.Now())
	event := &events.TagBatchDeletedEvent{
		IDs:       ids,
		TagInfos:  tagInfos,
		DeletedBy: 0, // 未登录系统或没有传入用户ID的情况
		DeletedAt: utils.TimeToJSONTime(now),
	}
	s.eventPublisher.AsyncPublish(ctx, events.NewEvent(events.TagBatchDeletedEventType, event))

	return nil
}

// GetTagStat 获取标签使用统计
func (s *service) GetTagStat(ctx context.Context, id uint) (*TagStatResponse, error) {
	// 检查标签是否存在
	tag, err := s.tagService.GetTag(ctx, id)
	if err != nil {
		return nil, WrapError(err)
	}
	if tag == nil {
		return nil, TagNotFound(id)
	}

	// 调用领域服务获取标签统计
	articleCount, bookCount, err := s.tagService.GetTagStat(ctx, id)
	if err != nil {
		return nil, WrapError(err)
	}

	return &TagStatResponse{
		ArticleCount: articleCount,
		BookCount:    bookCount,
		TotalCount:   articleCount + bookCount,
	}, nil
}
